package org.jiangwei.cmput696.entitylinking;

import java.io.File;
import java.io.IOException;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.jiangwei.cmput696.entitylinking.algorithm.SimpleCosineAlgorithm;
import org.jiangwei.cmput696.entitylinking.algorithm.UseMoreWordsAlgorithm;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class ELMain {

	private IELAlgorithm algorithm;

	public ELMain(IELAlgorithm algorithm) {
		this.algorithm = algorithm;
	}

	/**
	 * Process the query file. Store the results to <code>resultFilePath</code>.
	 * 
	 * @param queryFilePath
	 *            the query file path
	 * @param resultFilePath
	 *            the result file path
	 */
	public void process(String queryFilePath, String resultFilePath)
			throws QueryParsingException {
		ELQueryParser queryParser = new ELQueryParser();
		// parse the file for queries
		List<ELQuery> queries = queryParser.parse(queryFilePath);

		if (queries == null) {
			return;
		}

		DocumentBuilderFactory builderFactory = DocumentBuilderFactory
				.newInstance();
		DocumentBuilder docBuilder = null;
		try {
			docBuilder = builderFactory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			throw new QueryParsingException(
					"Failed to create document builder for saving results.", e);
		}
		Document doc = docBuilder.newDocument();

		// create root element
		Element rootElement = doc.createElement("kbpentlink");
		doc.appendChild(rootElement);

		for (ELQuery query : queries) {
			// search!
			List<ELCandidate> candidates = algorithm.search(query);
			// create elements for each query
			Element queryElement = doc.createElement("query");
			Attr attr = doc.createAttribute("id");
			attr.setValue(query.getId());
			queryElement.setAttributeNode(attr);

			Element nameElement = doc.createElement("name");
			nameElement.appendChild(doc.createTextNode(query.getSurface()));
			queryElement.appendChild(nameElement);

			for (ELCandidate candidate : candidates) {
				Element candidateElement = doc.createElement("candidate");
				candidateElement.appendChild(doc.createTextNode(candidate
						.getAnswer()));
				queryElement.appendChild(candidateElement);
			}

			Element docIdElement = doc.createElement("docid");
			docIdElement.appendChild(doc.createTextNode(query.getDocId()));
			queryElement.appendChild(docIdElement);

			rootElement.appendChild(queryElement);
		}

		StreamResult result = new StreamResult(new File(resultFilePath));
		DOMSource source = new DOMSource(doc);

		TransformerFactory transformerFactory = TransformerFactory
				.newInstance();
		try {
			Transformer transformer = transformerFactory.newTransformer();
			transformer.setOutputProperty(OutputKeys.INDENT, "yes");
			transformer.setOutputProperty(
					"{http://xml.apache.org/xslt}indent-amount", "2");
			transformer.transform(source, result);
		} catch (TransformerException e) {
			throw new QueryParsingException("Failed to transform the results.",
					e);
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		if (args.length < 2) {
			System.out
					.println("usage: ELMain <query_file> <result_file> [algo]");
			System.exit(-1);
		}
		// args = new
		// String[]{"/Users/wintokk/Dropbox/Research/cmput696/project/cmput696-asn-test/test_files/data/tac12-queries-dev.xml",
		// "/Users/wintokk/Dropbox/Research/cmput696/project/cmput696-asn-test/test_files/data/dev.out.xml"};
//		 args = new String[] {
//		 "../test_files/data/test5.xml",
//		 "../test_files/data/test5.out.xml" };
		try {
			//IELAlgorithm algorithm = new SimpleCosineAlgorithm();
		    IELAlgorithm algorithm = new UseMoreWordsAlgorithm();

			ELMain instance = new ELMain(algorithm);
			instance.process(args[0], args[1]);
		} catch (QueryParsingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
